#include "DemoController.h"

#define rm ResourcesManager::Get()

void cycki()
{
	const char *errorText = cgGetErrorString(cgGetError());
}

void ShowFPS(float ms)
{
	static int frames_count = 0;
	static float second = 0;
	static int act_frames = 0;
	static float time = 0;

	frames_count++;
	second += ms;

	time += ms;
	
	if (second >= 500.0f)
	{
		act_frames = frames_count * 2;

		second = 0;
		frames_count = 0;
	}

	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();
	gluOrtho2D(0, 1280, 0, 1024);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	glPushAttrib(GL_ENABLE_BIT);
	glDisable(GL_DEPTH_TEST);
	glDisable(GL_LIGHTING);
	glDisable(GL_BLEND);
	glDisable(GL_DEPTH_TEST);
	glDisable(GL_TEXTURE_2D);
	glRasterPos2d(0, 0);
	glRasterPos2d(2, 1006);
	glColor3f(1.0f, 1.0f, 1.0f);

	char txt_time[64];
	wsprintf(txt_time, "%u", act_frames);
	glCallLists((int)strlen(txt_time), GL_UNSIGNED_BYTE, txt_time);

	glRasterPos2d(0, 0);
	glRasterPos2d(2, 990);

	wsprintf(txt_time, "%u", (int)time);
	glCallLists((int)strlen(txt_time), GL_UNSIGNED_BYTE, txt_time);

	glPopAttrib();
	glMatrixMode(GL_PROJECTION);
	glPopMatrix();
	glMatrixMode(GL_MODELVIEW);
}

DemoController::DemoController(HDC hdc)
{
	this ->hdc = hdc;
}

DemoController::~DemoController(void)
{
	if (scene01 != NULL)
		delete scene01;

	/*if (scene02 != NULL)
		delete scene02;

	if (scene03 != NULL)
		delete scene03;*/

	if (context != NULL)
		cgDestroyContext(context);

	if (texMan != NULL)
		delete texMan;

	if (modelMan != NULL)
		delete modelMan;

	if (timeline != NULL)
		delete timeline;

	if (music != NULL)
		delete music;
}

bool DemoController::Initialize()
{
	time = 0.0f;

	char path[MAX_PATH + 1];
	GetCurrentDirectory(MAX_PATH + 1, path);
	baseDirectory = path;
	baseDirectory += "\\";

	SetOpenglParams();
	context = cgCreateContext();
	cgSetErrorCallback(cycki);
	cgGLSetDebugMode(CG_TRUE);

	animMan = new AnimationManager();
	animMan ->Load((baseDirectory + "data\\3d").c_str(), "ani");
	texMan = new TexturesManager();
	texMan ->Load((baseDirectory + "data\\textures").c_str(), "png");
	vertexShaderMan = new ShaderManager(context, CG_PROFILE_VP30);
	vertexShaderMan ->Load((baseDirectory + "data\\shaders").c_str(), "vpr");
	pixelShaderMan = new ShaderManager(context, CG_PROFILE_FP30);
	pixelShaderMan ->Load((baseDirectory + "data\\shaders").c_str(), "fpr");
	modelMan = new ModelManager(cgGetNamedParameter(vertexShaderMan ->Get("specular") ->GetProgram(), "modelViewProj"));
	modelMan ->Load((baseDirectory + "data\\3d").c_str(), "geo");
	matMan = new MaterialManager(texMan, vertexShaderMan ->Get("specular"), pixelShaderMan ->Get("specular"));
	matMan ->Load((baseDirectory + "data\\3d").c_str(), "mat");
	lightsManager = new LightsManager();
	lightsManager ->Load((baseDirectory + "data\\3d").c_str(), "lgt");
	camerasManager = new CamerasManager();
	camerasManager ->Load((baseDirectory + "data\\3d").c_str(), "cam");

	managers = new Managers();
	managers ->modelMan = modelMan;
	managers ->animMan = animMan;
	managers ->matMan = matMan;
	managers ->texMan = texMan;
	managers ->camerasManager = camerasManager;
	managers ->vertexShaderMan = vertexShaderMan;
	managers ->pixelShaderMan = pixelShaderMan;
	managers ->lightsManager = lightsManager;

	AssignMaterials();
	AssignAnimationToCameras();

	//anim = Animation::LoadFromFile("data\\3d\\scene03.ani");
	//Model *scene03Model = modelMan ->Get("scene03");
	//Mesh **meshes = scene03Model ->GetMeshes();
	//for (int i = 0; i < scene03Model ->GetMeshCount(); i++)
		//anim ->AttachAnimatable(meshes[i]);
	music = new Music();
	music ->LoadMusic((baseDirectory + "data\\music\\dementia.mp3").c_str());

	camerasManager ->Add("SteerCamera", new SteerCamera());

	tc = new TimeControl();
	timeline = new Timeline();
	timeline ->LoadFromFile((baseDirectory + "data\\scripts\\timeline.tml").c_str());

	scene01 = new Scene01(managers);
	scene01 ->Initialize();
	scene02 = new Scene02(managers);
	scene02 ->Initialize();
	scene03 = new Scene03(managers);
	scene03 ->Initialize();
	actScene = scene01;

	timeline ->RegisterObserver(this);
	timeline ->RegisterObserver(scene01);
	timeline ->RegisterObserver(scene02);
	timeline ->RegisterObserver(scene03);

	const char *extensions = (const char*)glGetString(GL_EXTENSIONS);

	time = 00000.0f;

	return true;
}

void DemoController::LoadData()
{
}

void DemoController::Start()
{
	tc ->Start();
	music ->Play();

	scene01 ->Prepare();
}

void DemoController::Process()
{
	float ms = tc ->CheckFrameMS();
	time += ms;

	timeline ->ProcessTime((int)time);

	actScene ->Render(ms);

	ShowFPS(ms);
	SwapBuffers(hdc);
}

void DemoController::Stop()
{
	if (music != NULL)
		music ->Stop();
}

void DemoController::SetOpenglParams()
{
	int wnd_width = 1280;
	int wnd_height = 1024;

	InitGlExtensions();

	wglUseFontBitmaps(hdc, 0, 255, 1000);
	glListBase(1000);

	glViewport(0, 0, wnd_width, wnd_height);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(60.0f, (float)wnd_width / (float)wnd_height, 0.1f, 1000.0f);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	glShadeModel(GL_SMOOTH);

	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
	glClearDepth(1.0f);
	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LEQUAL);

	glEnable(GL_NORMALIZE);

	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

	float l_pos[4] = {0.0f, 0.0f, 0.0f, 1.0f};
	float l_amb[4] = {0.5f, 0.5f, 0.5f, 1.0f};
	float l_dif[4] = {0.8f, 0.8f, 0.8f, 1.0f};
	glLightfv(GL_LIGHT0, GL_POSITION, l_pos);
	glLightfv(GL_LIGHT0, GL_AMBIENT, l_amb);
	glLightfv(GL_LIGHT0, GL_DIFFUSE, l_dif);
	glEnable(GL_LIGHT0);
	glEnable(GL_LIGHTING);
}

void DemoController::AssignMaterials()
{
	for (int i = 0; i < modelMan ->GetCount(); i++)
	{
		char name[128];
		Model *model;

		modelMan ->Get(i, name, model);

		MaterialsCollection *matCollection = matMan ->Get(name);
		if (matCollection != NULL)
			model ->AssignMaterials(matCollection);
	}
}

void DemoController::AssignAnimationToCameras()
{
}

void DemoController::Notify(float time, const char *type, const char *value)
{
	if (strcmp(type, "scene") == 0)
	{
		if (strcmp(value, "scene01") == 0)
		{
			scene01 ->Prepare();
			actScene = scene01;
		}

		if (strcmp(value, "scene02") == 0)
		{
			scene02 ->Prepare();
			actScene = scene02;
		}

		if (strcmp(value, "scene03") == 0)
		{
			scene03 ->Prepare();
			actScene = scene03;
		}
	}
}

